package concurrent.queue;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.Random;
import java.util.concurrent.*;

/**
 * @program JavaBase
 * @description:
 * @author: zhanglu
 * @create: 2021-05-23 19:57:00
 */
@Slf4j
public class QueueDemo {

    public void test01(){
        /*
            并发非阻塞无界队列(单向链表，入队出队CAS)：ConcurrentLinkedQueue
            有界链表阻塞队列(单向链表，入队出队ReentrantLock)：LinkedBlockingQueue
            有界数组阻塞队列(数组，入队出队ReentrantLock)：ArrayBlockingQueue
            带优先级无界阻塞队列(平衡二叉树，入队出队ReentrantLock，值越小优先级越高)：PriorityBlockingQueue
            无界阻塞延迟队列(基于优先队列，每个元素都有个过期时间，只有过期的元素才会出队列)：DelayQueue
         */
        /*
            通常情况：
            add/offer：尾部插入，有空闲则插入返回true；队列满了则丢弃当前元素返回false
            put：尾部插入，有空闲则插入；队列满了则阻塞当前线程，直到队列有空闲插入成功后返回，在此期间若中断线程，则抛出异常
            poll：头部获取并移除，队列为空返回null，不阻塞
            peek：头部获取不移除，队列为空返回null，不阻塞
            take：头部获取并移除，队列为空返回null，阻塞，直到队列不空后返回元素，在此期间若中断线程，则抛出异常
            remove：指定元素删除，有元素则删除返回true，反之false
         */
    }

    @Test
    public void test02() throws InterruptedException {
        PriorityBlockingQueue<PriorityBlockingQueueTask> priorityQueue = new PriorityBlockingQueue<>();
        new Thread(() -> {
            while (true){
                PriorityBlockingQueueTask poll = priorityQueue.poll();
                if(poll != null){
                    poll.todo();
                }
            }
        }).start();

        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            PriorityBlockingQueueTask task = new PriorityBlockingQueueTask();
            task.setPriority(random.nextInt(10));
            task.setTaskName("taskName" + i);
            priorityQueue.offer(task);
        }

        Thread.currentThread().join();

    }

    @Test
    public void test03(){
        DelayQueue<DelayQueueTask> delayQueue = new DelayQueue<>();
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            DelayQueueTask task = new DelayQueueTask(random.nextInt(10000), "task" + i);
            delayQueue.offer(task);
        }
        DelayQueueTask queueTask = null;
        while (true){
            try {
                while ((queueTask = delayQueue.take()) != null){
                    log.info(queueTask.toString());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Slf4j
    @Data
    private static class PriorityBlockingQueueTask implements Comparable<PriorityBlockingQueueTask>{

        private int priority = 0;
        private String taskName;

        @Override
        public int compareTo(PriorityBlockingQueueTask o) {
            if(this.priority >= o.getPriority()){
                return 1;
            }else {
                return -1;
            }
        }

        public void todo(){
            log.info(JSON.toJSONString(this));
        }

    }

    @NoArgsConstructor
    @Slf4j
    @Data
    private static class DelayQueueTask implements Delayed{

        //延迟时间
        private long delayTime;
        //到期时间
        private long expireTime;
        //任务名称
        private String taskName;

        public DelayQueueTask(long delayTime, String taskName) {
            this.delayTime = delayTime;
            this.taskName = taskName;
            this.expireTime = System.currentTimeMillis() + delayTime;
        }

        /**
         * 剩余时间 = 过期时间 - 当前时间
         * @param unit
         * @return
         */
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(this.expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }

        @Override
        public String  toString(){
            return JSON.toJSONString(this);
        }

    }

}
